
package com.example.filetransfer.publicsource.fileutils;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import com.example.filetransfer.publicsource.connection.Protocol;

public class DirDiffer {
    private List<MyFile> mChangedFiles = new ArrayList<MyFile>();
    private List<MyFile> mNewFiles = new ArrayList<MyFile>();
    private List<MyFile> mDeletedFils = new ArrayList<MyFile>();

    public List<MyFile> getChangedFiles() {
        return mChangedFiles;
    }

    public List<MyFile> getNewFiles() {
        return mNewFiles;
    }

    public List<MyFile> getDeletedFils() {
        return mDeletedFils;
    }

    public void compareDirFile(Dir oldDir, Dir newDir) {
        List<Dir> childOldDirs = oldDir.getChildDirs();
        List<Dir> childNewDirs = newDir.getChildDirs();
        List<Dir> childOldDirBk = new ArrayList<Dir>();
        List<Dir> childNewDirBk = new ArrayList<Dir>();
        childOldDirBk.addAll(childOldDirs);
        childNewDirBk.addAll(childNewDirs);
        int currentIndex = 0;
        for (Dir childNewDir : childNewDirs) {
            String newDirName = getDirName(childNewDir.dirName());
            for (int index = currentIndex; index < childOldDirs.size(); index++) {
                Dir childOldDir = childOldDirs.get(index);
                String oldDirName = getDirName(childOldDir.dirName());
                if (newDirName.equals(oldDirName)) {
                    compareDirFile(childOldDir, childNewDir);
                    childOldDirBk.remove(childOldDir);
                    childNewDirBk.remove(childNewDir);
                    currentIndex++;
                    break;
                } else if (index + 1 < childOldDirs.size()) {
                    if (newDirName.compareTo(childOldDirs.get(index + 1).dirName()) > 0) {
                        currentIndex++;
                        break;
                    }
                }
            }
        }
        if (childOldDirBk.size() > 0) {
            for (Dir dir : childOldDirBk) {
                mDeletedFils.addAll(DirUtils.listDirFiles(dir));
            }
        }
        if (childNewDirBk.size() > 0) {
            for (Dir dir : childNewDirBk) {
                mNewFiles.addAll(DirUtils.listDirFiles(dir));
            }
        }
        List<MyFile> childOldFiles = oldDir.getChildFiles();
        List<MyFile> childNewFiles = newDir.getChildFiles();
        comapreChildFiles(childOldFiles, childNewFiles);
    }

    private String getDirName(String dirPath) {
        return dirPath.substring(dirPath.lastIndexOf(File.separator));
    }

    public boolean timeSame(String t1, String t2) {
        long lt1 = Long.parseLong(t1);
        long lt2 = Long.parseLong(t2);
        return Math.abs(lt1 - lt2) < 1000;
    }

    private void comapreChildFiles(List<MyFile> childOldFiles, List<MyFile> newChildFiles) {
        List<MyFile> childOldFilesBk = new ArrayList<MyFile>();
        childOldFilesBk.addAll(childOldFiles);
        List<MyFile> childNewFilesBk = new ArrayList<MyFile>();
        childNewFilesBk.addAll(newChildFiles);

        int currentIndex = 0;
        for (MyFile childNewFile : newChildFiles) {
            String newFileName = DirUtils.getFileName(childNewFile.getFilePath());
            for (int index = currentIndex; index < childOldFiles.size(); index++) {
                MyFile childOldFile = childOldFiles.get(index);
                String oldFileName = DirUtils.getFileName(childOldFile.getFilePath());
                if (newFileName.equals(oldFileName)) {
                    if (!timeSame(childNewFile.getLastChanged(), childOldFile.getLastChanged())
                            && !Protocol.FILETREENAME.equals(newFileName)) {
                        mChangedFiles.add(childNewFile);
                    }
                    childNewFilesBk.remove(childNewFile);
                    childOldFilesBk.remove(childOldFile);
                    currentIndex++;
                    break;
                } else if (index + 1 < childOldFiles.size()) {
                    String nextOldFileName = childOldFiles.get(index + 1).getFilePath();
                    if (newFileName.compareTo(nextOldFileName) > 0) {
                        currentIndex++;
                        break;
                    }
                }
            }
        }
        if (childOldFilesBk.size() > 0) {
            mDeletedFils.addAll(childOldFilesBk);
        }
        if (childNewFilesBk.size() > 0) {
            mNewFiles.addAll(childNewFilesBk);
        }
    }

    public static void getFileTreeFile(final String dir, final String fileTreeName,
            final FileTreeCreatorListener fileTreeCreatorListener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                File file = new File(dir);
                Dir rootDir = DirUtils.scanDir(null, file);
                XmlSaver saver = new XmlSaver(fileTreeName);
                saver.saveDir(rootDir);
                fileTreeCreatorListener.onFileTreeCreated();
            }
        }).start();
    }

    public interface FileTreeCreatorListener {
        public void onFileTreeCreated();
    }

    // Test code
    public static List<MyFile> getDiff(String path) {
        List<MyFile> output = new ArrayList<MyFile>();
        // long start = System.currentTimeMillis();
        File file = new File(path);
        Dir rootDir = DirUtils.scanDir(null, file);
        String filetreeName = DirUtils.createFile(file.getAbsolutePath(), ".filetree.xml");
        File fileTree = new File(filetreeName);
        if (fileTree.exists()) {
            XmlReader xmlReader = new XmlReader();
            xmlReader.parserXml(filetreeName);
            Dir rootDir2 = xmlReader.getRootDir();
            DirDiffer dirDiffer = new DirDiffer();
            dirDiffer.compareDirFile(rootDir2, rootDir);
            output.addAll(dirDiffer.mChangedFiles);
            output.addAll(dirDiffer.mNewFiles);
        } else {
            System.out.println("file tree doesn't exist create a new one");
            XmlSaver saver = new XmlSaver(DirUtils.createFile(file.getAbsolutePath(), ".filetree.xml"));
            saver.saveDir(rootDir);
            output.addAll(DirUtils.listDirFiles(rootDir));
        }
        return output;
    }

}
